from EmpVotingTestBed import ExpResults
from EmpVoting.Alg.SwIntrinsicUtilAlg import SwIntrinsicUtilAlg

class Experiment(object):

    def __init__(self, runnableObj, numRuns, testBedStatConfig, testBedOutputConfig):
        '''
        Constructor
        
        runnableObj can be an object with a Run() function or a list of objects with Run() functions.
        '''
        self.RunnableObj = runnableObj
        self.NumRuns = numRuns
        self.TestBedStatConfig = testBedStatConfig
        self.TestBedOutputConfig = testBedOutputConfig
        
    def Run(self):
        expResults = ExpResults()
        
        if not isinstance(self.RunnableObj, list):
            self.RunnableObj = [self.RunnableObj]
        
        for i in range(0, self.NumRuns):
            for runableObj in self.RunnableObj:
                result = runableObj.Run()
                
                #Output and stats are only applied to the last runnable object
                if runableObj != self.RunnableObj[-1]:
                    continue
                
                for fieldName, fieldValue in result.__dict__.items():
                    if fieldName == "graph" or fieldName == "agentList":
                        continue
                    
                    if not (hasattr(expResults, fieldName)):
                        expResults.__dict__[fieldName] = []
                    
                    expResults.__dict__[fieldName].append(fieldValue)
                
        self.TestBedStatConfig.Apply(expResults)
        self.TestBedOutputConfig.Apply(expResults)
        
        return expResults


def Main():
    from EmpVoting import EmpEngine
    
    from EmpVoting.Alg import AlgConfig
    from EmpVoting.Alg import AgentWeightGlobalAlg
    from EmpVoting.Alg import AgentUtilGlobalAlg
    from EmpVoting.Alg import SwFromAgentWeightAlg
    from EmpVoting.Alg import SwLocalAlg
    from EmpVoting.Alg import SwGlobalAlg
    
    from EmpVoting.Gen import NetworkGen
    from EmpVoting.Gen.AgentGen import UniformRandomPrefsAgentGen
    from EmpVoting.Gen.EdgeGen.BinomialEdgeGen import BinomialEdgeGen
    from EmpVoting.Gen.EdgeGen.SelfLoopEdgeGen import SelfLoopEdgeGen
    from EmpVoting.Gen.EdgeGen.EvenDistWeightsEdgeGen import EvenDistWeightsEdgeGen
    from EmpVoting.Gen.GenFromFile import GenFromFile
    
    from EmpVoting.Stat import StatConfig
    from EmpVoting.Stat import NetworkStatFromAgentField
    from EmpVoting.Stat import RswlStats
    
    from EmpVoting.EmpUtils import ScoringRulesEnum
    from EmpVoting.Output import NetworkSerializer
    from EmpVoting.Output import OutputConfig
    from EmpVoting.PythonUtils import XmlSerializer
    
    from EmpVotingTestBed.Stat import TestBedStatConfig
    from EmpVotingTestBed.Stat import ExperimentStatFromNetworkField
    
    from EmpVotingTestBed.Output import TestBedOutputConfig
    from EmpVotingTestBed.Output import TestBedSpreadsheetWriter
    
    numNodes = 20
    numAlternatives = 3
    
    agentGenList = []
    agentGenList.append(UniformRandomPrefsAgentGen(ScoringRulesEnum.Plurality))

    edgeProb = 2.0 / numNodes
    selfLoopWeight = 0.4

    edgeGenList = []
    edgeGenList.append(BinomialEdgeGen(edgeProb))
    edgeGenList.append(SelfLoopEdgeGen())
    edgeGenList.append(EvenDistWeightsEdgeGen(selfLoopWeight))
    
    netGen = NetworkGen(numNodes, numAlternatives, agentGenList, edgeGenList)
        
    algList = [SwLocalAlg(True),
               SwGlobalAlg(True),
               SwIntrinsicUtilAlg(True)]

    algConfig = AlgConfig(algList)
    
    statList = [NetworkStatFromAgentField("inDegree", "distribution"),
                RswlStats()]
    statConfig = StatConfig(statList)
    
    
    networkSerializer = NetworkSerializer("graphml")
    outputConfig = OutputConfig([networkSerializer])
        
    empEngine = EmpEngine(GenFromFile("C:\\Rob\\Dropbox\\Repos\\emp-voting\\EmpVotingTestBed\\src\\EmpVotingTestBed\\network.graphml", "graphml"), algConfig, statConfig, outputConfig)
    
    testBedStatList = [ExperimentStatFromNetworkField("bestAlternative", "distribution")]
    testBedStatConfig = TestBedStatConfig(testBedStatList)
    
    testBedOutputList = [TestBedSpreadsheetWriter()]
    testBedOutputConfig = TestBedOutputConfig(testBedOutputList)
    
    experiment = Experiment(empEngine, 10, testBedStatConfig, testBedOutputConfig)
    xmlSerializer = XmlSerializer()
    xmlConfig = xmlSerializer.Serialize(experiment)
    
    configFile = open("..\\dist\\generated-config.xml", 'w')
    configFile.write(xmlConfig)
    configFile.close()
    
    experiment.Run()
    
#Sample usage
if __name__ == "__main__":
    Main()
